#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/epoll.h>
#include "Channel.h"
#include "EventLoop.h"

#define MAX 1024

struct EpollData
{
    int32_t epfd;
    struct epoll_event *events;
};

static void *epollInit();
static int32_t epollAdd(struct Channel *channel, struct EventLoop *evLoop);
static int32_t epollRemove(struct Channel *channel, struct EventLoop *evLoop);
static int32_t epollModify(struct Channel *channel, struct EventLoop *evLoop);
static int32_t epollDispatch(struct EventLoop *evLoop, int32_t timeout);
static int32_t epollClear(struct EventLoop *evLoop);
static int32_t epollCtl(struct Channel *channel, struct EventLoop *evLoop, int8_t optional);

struct Dispatcher EpollDispatcher =
    {
        epollInit,
        epollAdd,
        epollRemove,
        epollModify,
        epollDispatch,
        epollClear};

static void *epollInit()
{
    struct EpollData *epollData = (struct EpollData *)malloc(sizeof(struct EpollData));
    if (epollData == NULL)
    {
        perror("malloc error");
        exit(0);
    }
    int32_t epfd = epoll_create(10);
    epollData->epfd = epfd;
    epollData->events = (struct epoll_event *)calloc(MAX, sizeof(struct epoll_event));
    if (epollData->events == NULL)
    {
        perror("calloc error");
        exit(0);
    }
    return epollData;
}

static int32_t epollAdd(struct Channel *channel, struct EventLoop *evLoop)
{
    if (epollCtl(channel, evLoop, EPOLL_CTL_ADD) == -1)
    {
        perror("epollCtl add failed");
        return -1;
    }
    return 0;
}

static int32_t epollRemove(struct Channel *channel, struct EventLoop *evLoop)
{
    if (epollCtl(channel, evLoop, EPOLL_CTL_DEL) == -1)
    {
        perror("epollCtl delete failed");
        return -1;
    }
    //通过channel释放对于的tcpConnection资源
    printf("释放channel -- channel->fd = %d\n", channel->fd);
    channel->destroyCallback(channel->arg);
    return 0;
}

static int32_t epollModify(struct Channel *channel, struct EventLoop *evLoop)
{
    if (epollCtl(channel, evLoop, EPOLL_CTL_MOD) == -1)
    {
        perror("epollCtl modify failed");
        return -1;
    }
    return 0;
}

static int32_t epollDispatch(struct EventLoop *evLoop, int32_t timeout)
{
    struct EpollData *data = (struct EpollData *)evLoop->dispatcherData;
    int32_t count = epoll_wait(data->epfd, data->events, MAX, timeout * 1000);
    if (count < 0)
    {
        perror("epoll_wait error");
    }
    for (int32_t i = 0; i < count; i++)
    {   
        int32_t events = data->events[i].events;
        int fd = data->events[i].data.fd;
        if (events & (EPOLLHUP | EPOLLRDHUP | EPOLLERR))
        {
            // 对方断开了连接，删除fd
            //  epollRemove(Channel,evLoop);
            // printf("%s epollDispatch : epoll_wait cfd = %d对方断开了连接\n",evLoop->threadName, fd);
            continue;
        }
        if (events & EPOLLIN)
        {
            // printf("%s epollDispatch : epoll_wait cfd = %d可读\n",evLoop->threadName, fd);
            eventActivate(evLoop, fd, ReadEvent);
        }
        if (events & EPOLLOUT)
        {   
            // printf("%s epollDispatch : epoll_wait cfd = %d可写\n",evLoop->threadName, fd);
            eventActivate(evLoop, fd, WriteEvent);
        }
    }
    return 0;
}

static int32_t epollClear(struct EventLoop *evLoop)
{
    struct EpollData *data = (struct EpollData *)evLoop->dispatcherData;
    free(data->events);
    close(data->epfd);
    free(data);
}

static int32_t epollCtl(struct Channel *channel, struct EventLoop *evLoop, int8_t optional)
{
    struct EpollData *data = (struct EpollData *)evLoop->dispatcherData;
    struct epoll_event ev;
    ev.data.fd = channel->fd;
    int events = 0;
    if (channel->events & ReadEvent)
    {
        events |= EPOLLIN;
    }
    if (channel->events & WriteEvent)
    {
        events |= EPOLLOUT;
    }
    ev.events = events;
    if (epoll_ctl(data->epfd, optional, channel->fd, &ev) == -1)
    {
        perror("epoll_ctl failed");
        return -1;
    }

    return 0;
}
